package com.ym.soso.common.utils;

import java.math.BigDecimal;
import java.text.NumberFormat;


/**
 * 四则运算
 *
 * @author lt
 * @version 2018年11月10日上午9:15:02
 */
public class CalcUtil {

    /**
     * 保留小数位
     */
    private static final int DEF_DIV_SCALE = 4;

    /**
     * 结果值
     */
    private BigDecimal currNum = null;

    private CalcUtil(BigDecimal decimal) {
        currNum = decimal;
    }

    /**
     * 判断一个数字是否是decimal，不是的话，转换包装
     *
     * @param v1
     * @return
     */
    private static BigDecimal covertToDecimal(Number v1) {
        BigDecimal value;
        if (v1 instanceof BigDecimal) {
            value = (BigDecimal) v1;
        } else {
            value = new BigDecimal(v1.toString());
        }
        return value;
    }

    /**
     * 初始化运算对象
     *
     * @param v1
     * @return
     */
    public static CalcUtil init(Number v1) {
        return new CalcUtil(covertToDecimal(v1));
    }

    /**
     * 直接相加
     *
     * @return
     */
    public static CalcUtil addDirect(Number... v2) {
        BigDecimal value = BigDecimal.ZERO;
        for (Number number : v2) {
            value = value.add(covertToDecimal(number));
        }
        return new CalcUtil(value);
    }

    /**
     * 运算结果后，跟着相加
     *
     * @param v1
     * @return
     */
    public CalcUtil add(Number... v1) {
        for (Number number : v1) {
            this.currNum = this.currNum.add(covertToDecimal(number));
        }
        return this;
    }

    /**
     * 两数直接相减
     *
     * @param v2 被减数
     * @return
     */
    public static CalcUtil subDirect(Number... v2) {
        BigDecimal value = BigDecimal.ZERO;
        for (Number number : v2) {
            value = value.subtract(covertToDecimal(number));
        }
        return new CalcUtil(value);
    }

    /**
     * 运算结果后，跟着相减
     *
     * @param v1 减数
     * @return
     */
    public CalcUtil sub(Number... v1) {
        for (Number number : v1) {
            this.currNum = this.currNum.subtract(covertToDecimal(number));
        }
        return this;
    }

    /**
     * 两数直接相乘
     *
     * @param v2
     * @return
     */
    public static CalcUtil mulDirect(Number... v2) {
        BigDecimal value = BigDecimal.ZERO;
        for (Number number : v2) {
            value = value.multiply(covertToDecimal(number));
        }
        return new CalcUtil(value);
    }

    /**
     * 运算结果后，跟着相乘
     *
     * @param v1
     * @return
     */
    public CalcUtil mul(Number... v1) {
        for (Number number : v1) {
            this.currNum = this.currNum.multiply(covertToDecimal(number));
        }
        return this;
    }

    /**
     * 两数直接相除
     *
     * @param v2 被除数
     * @return
     */
    public static CalcUtil divDirect(Number... v2) {
        BigDecimal value = BigDecimal.ZERO;
        for (Number number : v2) {
            // 此处保留20位，减少误差
            value = value.divide(covertToDecimal(number), 20, BigDecimal.ROUND_HALF_UP);
        }
        return new CalcUtil(value);
    }

    /**
     * 运算结果后，跟着相除
     *
     * @param v1 除数
     * @return
     */
    public CalcUtil div(Number... v1) {
        for (Number number : v1) {
            // 此处保留20位，减少误差
            this.currNum = this.currNum.divide(covertToDecimal(number), 20, BigDecimal.ROUND_HALF_UP);
        }
        return this;
    }

    /**
     * 返回结果,可不传参数
     *
     * @param scale 保留位数，默认2位小数
     * @return
     */
    public float floatValue(int... scale) {
        if (scale.length > 0) {
            return currNum.setScale(scale[0], BigDecimal.ROUND_HALF_UP).floatValue();
        }
        return currNum.setScale(DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * 返回结果,可不传参数
     *
     * @param scale 保留位数，默认2位小数
     * @return
     */
    public long longValue(int... scale) {
        if (scale.length > 0) {
            return currNum.setScale(scale[0], BigDecimal.ROUND_HALF_UP).longValue();
        }
        return currNum.setScale(DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).longValue();
    }

    /**
     * 返回结果,可不传参数
     *
     * @param scale 保留位数，默认2位小数
     * @return
     */
    public int intValue(int... scale) {
        if (scale.length > 0) {
            return currNum.setScale(scale[0], BigDecimal.ROUND_HALF_UP).intValue();
        }
        return currNum.setScale(DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).intValue();
    }

    /**
     * 返回结果,可不传参数
     *
     * @param scale 保留位数，默认2位小数
     * @return
     */
    public double doubleValue(int... scale) {
        if (scale.length > 0) {
            return currNum.setScale(scale[0], BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        return currNum.setScale(DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 返回结果,可不传参数
     *
     * @param scale 保留位数，默认2位小数
     * @return
     */
    public short shortValue(int... scale) {
        if (scale.length > 0) {
            return currNum.setScale(scale[0], BigDecimal.ROUND_HALF_UP).shortValue();
        }
        return currNum.setScale(DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).shortValue();
    }

    /**
     * 返回结果,可不传参数
     *
     * @param scale 保留位数，默认2位小数
     * @return
     */
    public BigDecimal decimalValue(int... scale) {
        if (scale.length > 0) {
            return currNum.setScale(scale[0], BigDecimal.ROUND_HALF_UP);
        }
        return currNum.setScale(DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 返回字符串值
     *
     * @param thousands 是否千分符
     * @param scale     保留几位小数
     * @return
     */
    public String stringValue(boolean thousands, int... scale) {
        BigDecimal bigDecimal = decimalValue(scale);
        NumberFormat numberFormat = NumberFormat.getInstance();
        if (scale.length > 0) {
            numberFormat.setMinimumFractionDigits(scale[0]);
        } else {
            numberFormat.setMinimumFractionDigits(DEF_DIV_SCALE);
        }
        numberFormat.setGroupingUsed(thousands);
        return numberFormat.format(bigDecimal);
    }

}